package com.imooc.imoocbilibili.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imooc.imoocbilibili.entity.*;
import com.imooc.imoocbilibili.exception.RRException;
import com.imooc.imoocbilibili.interceptor.ThreadUser;
import com.imooc.imoocbilibili.mapper.VideoMapper;
import com.imooc.imoocbilibili.service.*;
import com.imooc.imoocbilibili.utils.FastDFSUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

@Service("videoService")
@RequiredArgsConstructor
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements VideoService {

    private final VideoTagService videoTagService;
    private final VideoLikeService videoLikeService;
    private final VideoCollectionService videoCollectionService;
    private final UserCoinService userCoinService;
    private final VideoCoinService videoCoinService;
    private final UserInfoService userInfoService;
    private final FastDFSUtil fastDFSUtil;


    @Override
    public Page<Video> queryPage(Integer pageNo, Integer pageSize, String area) {
        Page<Video> page = this.page(
                new Page<>(pageNo, pageSize),
                // 拼接查询条件
                new LambdaQueryWrapper<Video>()
                        .eq(StrUtil.isNotBlank(area), Video::getArea, area)
        );

        return page;
    }

    @Override
    @Transactional
    public void addVideos(Video video) {
        Long useId = ThreadUser.getUser().getId();
        video.setUserid(useId);
        video.setCreatetime(new Date());
        this.save(video);

        List<VideoTag> videoTags = video.getVideoTags();
        videoTags.forEach(videoTag -> {
            videoTag.setCreatetime(new Date());
            videoTag.setVideoid(video.getId());
        });
        videoTagService.saveBatch(videoTags);
    }

    @Override
    public void viewVideoOnlineBySlices(HttpServletRequest request, HttpServletResponse response, String path) throws Exception {
        fastDFSUtil.viewVideoOnlineBySlices(request, response, path);
    }

    @Override
    public void addVideoLike(Long videoId) {
        if (this.getById(videoId) == null) {
            throw new RRException("视频不存在");
        }

        if (videoLikeService.getOne(new LambdaQueryWrapper<VideoLike>().eq(VideoLike::getVideoid, videoId)
                .eq(VideoLike::getUserid, update())) != null) {
            throw new RRException("已经点赞");
        }

        Long useId = ThreadUser.getUser().getId();
        VideoLike videoLike = new VideoLike();
        videoLike.setVideoid(videoId);
        videoLike.setUserid(useId);
        videoLike.setCreatetime(new Date());
        videoLikeService.save(videoLike);
    }

    @Override
    public void deleteVideoLike(Long videoId) {
        Long useId = ThreadUser.getUser().getId();
        videoLikeService.remove(new LambdaQueryWrapper<VideoLike>().eq(VideoLike::getUserid, useId)
                .eq(VideoLike::getVideoid, videoId));
    }

    @Override
    public Map<String, Object> getVideoLike(Long videoId) {
        Map<String, Object> result = new HashMap<>();
        long count = videoLikeService.count(new LambdaQueryWrapper<VideoLike>().eq(VideoLike::getVideoid, videoId));
        result.put("count", count);
        result.put("like", false);

        // 当前用户是否对该视频点赞过
        if (ThreadUser.getUser() != null) {
            Long userId = ThreadUser.getUser().getId();
            long number = videoLikeService.count(new LambdaQueryWrapper<VideoLike>().eq(VideoLike::getVideoid, videoId)
                    .eq(VideoLike::getUserid, userId));
            result.put("like", number > 0);
        }
        return result;
    }

    @Transactional
    public void addVideoCollection(VideoCollection videoCollection) {
        Long userId = ThreadUser.getUser().getId();
        Long videoId = videoCollection.getVideoid();
        Long groupId = videoCollection.getGroupid();
        if (videoId == null || groupId == null) {
            throw new RRException("参数异常！");
        }
        Video video = this.getById(videoId);
        if (video == null) {
            throw new RRException("非法视频！");
        }
        //删除原有视频收藏
        videoCollectionService.remove(new LambdaQueryWrapper<VideoCollection>().eq(VideoCollection::getVideoid, videoId)
                .eq(VideoCollection::getUserid, userId));
        //添加新的视频收藏
        videoCollection.setUserid(userId);
        videoCollection.setCreatetime(new Date());
        videoCollectionService.save(videoCollection);
    }

    @Override
    public void deleteVideoCollection(Long videoId) {
        Long userId = ThreadUser.getUser().getId();
        videoCollectionService.remove(new LambdaQueryWrapper<VideoCollection>().eq(VideoCollection::getVideoid, videoId)
                .eq(VideoCollection::getUserid, userId));
    }

    @Override
    public Map<String, Object> getVideoCollections(Long videoId) {
        Map<String, Object> result = new HashMap<>();
        Long count = videoCollectionService.count(new LambdaQueryWrapper<VideoCollection>().eq(VideoCollection::getVideoid, videoId));
        result.put("count", count);
        result.put("like", false);

        if (ThreadUser.getUser() != null) {
            Long userId = ThreadUser.getUser().getId();
            long number = videoCollectionService.count(new LambdaQueryWrapper<VideoCollection>().eq(VideoCollection::getVideoid, videoId)
                    .eq(VideoCollection::getUserid, userId));
            result.put("like", number > 0);
        }
        return result;
    }

    @Transactional
    public void addVideoCoins(VideoCoin videoCoin) {
        Long userId = ThreadUser.getUser().getId();
        Long videoId = videoCoin.getVideoid();
        Integer amount = videoCoin.getAmount();
        if (videoId == null) {
            throw new RRException("参数异常！");
        }
        Video video = this.getById(videoId);
        if (video == null) {
            throw new RRException("非法视频！");
        }
        //查询当前登录用户是否拥有足够的硬币
        UserCoin userCoin = userCoinService.getOne(new LambdaQueryWrapper<UserCoin>().eq(UserCoin::getUserId, userId));
        Long userCoinsAmount = userCoin.getAmount();
        userCoinsAmount = userCoinsAmount == null ? 0 : userCoinsAmount;
        if (amount > userCoinsAmount) {
            throw new RRException("硬币数量不足！");
        }

        //查询当前登录用户对该视频已经投了多少硬币
        VideoCoin dbVideoCoin = videoCoinService.getOne(new LambdaQueryWrapper<VideoCoin>().eq(VideoCoin::getVideoid, videoId)
                .eq(VideoCoin::getUserid, userId));

        //新增视频投币
        if (dbVideoCoin == null) {
            videoCoin.setUserid(userId);
            videoCoin.setCreatetime(new Date());
            videoCoinService.save(videoCoin);
        } else {
            Integer dbAmount = dbVideoCoin.getAmount();
            dbAmount += amount;
            //更新视频投币
            videoCoin.setAmount(dbAmount);
            videoCoin.setUpdatetime(new Date());
            videoCoinService.updateById(videoCoin);
        }

        //更新用户当前硬币总数
        userCoin.setAmount(userCoinsAmount - amount);
        userCoinService.updateById(userCoin);
    }

    @Override
    public Map<String, Object> getVideoCoins(Long videoId) {
        Map<String, Object> result = new HashMap<>();
        List<VideoCoin> videoCoins = videoCoinService.list(new LambdaQueryWrapper<VideoCoin>().eq(VideoCoin::getVideoid, videoId));
        Integer count = videoCoins.stream().mapToInt(VideoCoin::getAmount).sum();
        result.put("count", count);
        result.put("like", false);

        if (ThreadUser.getUser() != null) {
            Long userId = ThreadUser.getUser().getId();
            long number = videoCoinService.count(new LambdaQueryWrapper<VideoCoin>().eq(VideoCoin::getVideoid, videoId)
                    .eq(VideoCoin::getUserid, userId));
            result.put("like", number > 0);
        }

        return result;
    }

    @Override
    public Map<String, Object> getVideoDetails(Long videoId) {
        Video video =  this.getById(videoId);
        Long userId = video.getUserid();
        UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserid, userId));
        Map<String, Object> result = new HashMap<>();
        result.put("video", video);
        result.put("userInfo", userInfo);
        return result;
    }


}